package in.srain.cube.concurrent;

import android.os.SystemClock;
import androidx.annotation.Nullable;

import java.util.UUID;

public class RunnableWrapper implements Runnable {

    private final RunnableHook mRunnableHook;
    private final Runnable mRunnable;
    private final Exception mStarterStackTrace;
    private final String mId;
    private long mStart;
    private long mEnd;
    private Thread mThread;

    public RunnableWrapper(RunnableHook runnableHook, Runnable runnable) {
        this.mRunnableHook = runnableHook;
        this.mRunnable = runnable;
        this.mId = UUID.randomUUID().toString();
        this.mStarterStackTrace = new Exception();
    }

    @Override
    public void run() {
        mThread = Thread.currentThread();
        mStart = SystemClock.elapsedRealtime();
        mRunnableHook.beforeExecute(mThread, this);

        Throwable throwable = null;
        try {
            mRunnable.run();
        } catch (Throwable t) {
            throwable = t;
            throw t;
        } finally {
            mEnd = SystemClock.elapsedRealtime();
            mRunnableHook.afterExecute(this, throwable);
        }
    }

    public Runnable getRunnable() {
        return mRunnable;
    }

    public Exception getStarterStackTrace() {
        return mStarterStackTrace;
    }

    public String getId() {
        return mId;
    }

    public long getDuration() {
        final long end = mEnd;
        return end == 0 ? 0 : end - mStart;
    }

    public long getStartFromNow() {
        return SystemClock.elapsedRealtime() - mStart;
    }

    public long getDurationOrStartFromNow() {
        final long duration = getDuration();
        return duration != 0 ? duration : getStartFromNow();
    }

    @Nullable
    public Thread getThread() {
        return mThread;
    }
}
